#ifndef BUS_H
#define BUS_H

//Author: Nathan Sandoval

#include <systemc.h>
#include <iostream>
#include <vector>
#include <map>
#include <vector>
//uncomment this to dump all
//bus transaction info to the stdout
//you can see exactly how messages are being passed between modules.
//#define DEBUG_BUS 1

//uncomment this and the define in top.h to enable approximate time profiling
#define APPROXIMATE_TIMED 1

/*
 * Bus interface containing a master and a slave interface.
 * This bus uses a round robin arbitration scheme
 * IMPORTANT: Each master must have a unique id!
 *
 * Error handling:
 * The bus WaitForAcknowledge function returns true or false if an acknowledge was received from a slave device
 * It is the designers responsibility to handle that error. If unhandled, the system will freeze if a Master tries to read, or do something when the
 * request was not acknowledged.
 *
 * the SC_THREAD of this module is called "arbitrate".
 */


#define	NathanNamespaceBegin	namespace NathanNamespace {
#define	NathanNamespaceEnd		}

NathanNamespaceBegin


using namespace std;
// Bus Master Interface
class bus_master_if : virtual public sc_interface
{
public:
    virtual void Request(unsigned mst_id, unsigned addr, unsigned op, unsigned len) = 0;
    virtual bool WaitForAcknowledge(unsigned mst_id) = 0;
    virtual void ReadData(unsigned &data) = 0;
    virtual void WriteData(unsigned data) = 0;
};

// Bus Servant Interface
class bus_servant_if : virtual public sc_interface
{
public:
    virtual void Listen(unsigned &req_addr, unsigned &req_op, unsigned &req_len) = 0;
    virtual void Acknowledge() = 0;
    virtual void SendReadData(unsigned data) = 0;
    virtual void ReceiveWriteData(unsigned &data) = 0;
};

class bus : public sc_channel, public bus_master_if, public bus_servant_if
{

public:

    SC_HAS_PROCESS(bus);
    bus(sc_module_name name);

    virtual ~bus();

// for request operations: op == 0 means read, op == 1 means write
    void Request(unsigned mst_id, unsigned addr, unsigned op, unsigned len);
    bool WaitForAcknowledge(unsigned mst_id);
    void ReadData(unsigned &data);
    void WriteData(unsigned data);
    void Listen(unsigned &req_addr, unsigned &req_op, unsigned &req_len);
    void Acknowledge();
    void SendReadData(unsigned data);
    void ReceiveWriteData(unsigned &data);



    void arbitrate();

    /* these events represent the following:
     * receivedCmd is a slave device acknowledging to the bus that it acknowledges a requests
     * cmdAck is the bus forwarding the acknowledge to the master
     * readData is the master informing that it has read some data sent by a slave
     * wroteData is a master informing that it has written some data to the bus for a slave to readData
     * sentReadData is a slave informing that it has sent some data for a master to read
     * receivedWriteData is a slave informing that it has received data that was sent by a master to be written
     * publishRequest is the bus informing the slave devices of a new request
     * masterRequest is a master informing the bus that it has sent a request.
     */
    sc_event receivedCmd, cmdAck, readData, wroteData, sentReadData, receivedWriteData, publishRequest, masterRequest, receivedRejection;


    bool ack; //used to forward a true or false acknowledge to a master

    //current operation detail variables.
    unsigned currentData, currentId, currentAddr, currentOp, currentLen; //represents the current data, and operation


    //map of vectors containing request information.
    map<unsigned, vector<unsigned> > requests;

    //mapping of number of ids that have made requests to the actual id number in order that requests were sentReadData
    vector<unsigned> masterIDs;

    //current number of master components that have made requests to the bus
    unsigned num_components;


};



NathanNamespaceEnd

#endif // BUS_H
